﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;

namespace WorkNodeFramework
{
    public abstract class Query<T>:Query
        where T:Query<T>
    {
        public T From(ITable table)
        {
            TableList.Add(table);
            return (T)this;
        }

        public T From(string tableName) {
            TableList.Add(new StringTable(tableName));
            return (T)this;
        }

        public T From<TEntity>()
            where TEntity : IEntity, new()
        {
            TableList.Add((new TEntity()).Table);
            return (T)this;
        }

        public T Where(params IWhereCondition[] conditions) {
            if (conditions.Length == 1)
                this.Conditions.Add(conditions[0]);
            else
            {
                IWhereCondition condition = WHERE.AND(conditions);
                this.Conditions.Add(condition);
            }
            return (T)this;
        }

        public InnerJoin<T> InnerJoin(ITable table)
        {
            InnerJoin<T> join = new InnerJoin<T>(this, table);
            JoinClauses.Add(join);
            return join;
        }

        public LeftOuterJoin<T> LeftOuterJoin(ITable table) {
            LeftOuterJoin<T> join = new LeftOuterJoin<T>(this, table);
            base.JoinClauses.Add(join);
            return join;
        }

        public RightOuterJoin<T> RightOuterJoin(ITable table) {
            RightOuterJoin<T> join = new RightOuterJoin<T>(this, table);
            base.JoinClauses.Add(join);
            return join;
        }

        public FullOuterJoin<T> FullOuterJoin(ITable table) {
            FullOuterJoin<T> join = new FullOuterJoin<T>(this, table);
            base.JoinClauses.Add(join);
            return join;
        }

        public T CrossJoin(ITable table) {
            CrossJoin join = new CrossJoin(table);
            base.JoinClauses.Add(join);
            return (T)this;
        }
    }

    public abstract class Query
    {
        List<ITable> tableList = new List<ITable>();
        List<IWhereCondition> conditions = new List<IWhereCondition>();
        List<IJoinClause> joinClauses = new List<IJoinClause>();

        internal List<ITable> TableList
        {
            get
            {
                return tableList;
            }
        }

        internal List<IWhereCondition> Conditions
        {
            get
            {
                return conditions;
            }
        }

        internal List<IJoinClause> JoinClauses {
            get {
                return joinClauses;
            }
        }

        DataProvider provider;
        public DataProvider Provider
        {
            get
            {
                if (provider != null)
                    return provider;
                return DataService.Provider;
            }
            internal set
            {
                provider = value;
            }
        }

        protected string BuildQueryStatement()
        {
            ParameterIndexCollection pars = new ParameterIndexCollection();
            return BuildQueryStatement(pars);
        }

        protected string BuildQueryStatement(ParameterIndexCollection parameters)
        {
            return Provider.BuildQueryStatement(this, parameters);
        }
    }
}
